package sg.edu.nus.iss.billing.controller;

import java.util.ArrayList;
import java.util.List;

import sg.edu.nus.iss.billing.constant.ErrorCodeConstants;
import sg.edu.nus.iss.billing.datastore.DBFactory;
import sg.edu.nus.iss.billing.datastore.IDataStore;
import sg.edu.nus.iss.billing.datastore.impl.Selector;
import sg.edu.nus.iss.billing.entity.Account;
import sg.edu.nus.iss.billing.entity.Customer;
import sg.edu.nus.iss.billing.entity.RecordState;
import sg.edu.nus.iss.billing.exception.ControllerException;
import sg.edu.nus.iss.billing.exception.DataStoreException;
import sg.edu.nus.iss.billing.localization.MessageKeyManager;
import sg.edu.nus.iss.billing.util.Util;

public class CustomerController {

	private IDataStore dataStorage;

	public CustomerController() {
		dataStorage = DBFactory.instance().getSDStore();
	}

	public List<Customer> getAllCustomers() throws ControllerException {
		List<Customer> customerList = new ArrayList<Customer>();
		AccountController accountController = new AccountController();
		Selector selector = new Selector();
		selector.eq("active", RecordState.ACTIVE);
		try {
			customerList = dataStorage.loadObjectsBySelector(Customer.class,
					selector);
			for (Customer customer: customerList) {
				customer.setAccount(accountController.getAccountByNRIC(customer.getNRIC()));
			}
		} catch (DataStoreException e) {
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		return customerList;
	}

	public Customer isNRICExist(String nric) throws ControllerException {
		List<Customer> customerList = null;
		Customer customerObj = null;
		Selector selector = new Selector();
		selector.eq("NRIC", nric.toUpperCase());
		try {
			customerList = dataStorage.loadObjectsBySelector(Customer.class,
					selector);
		} catch (DataStoreException e) {
			e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (!Util.isEmpty(customerList)) {
			customerObj = customerList.get(0);
		}
		return customerObj;
	}

	public Customer getCustomerByNRIC(String nric) throws ControllerException {
		List<Customer> customerList = null;
		Customer customerObj = null;
		Account accountObj = null;
		String accountNumber = null;
		AccountController accountController = new AccountController();
		Selector selector = new Selector();
		selector.eq("NRIC", nric.toUpperCase());
		try {
			customerList = dataStorage.loadObjectsBySelector(Customer.class,
					selector);
		} catch (DataStoreException e) {
			// e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (!Util.isEmpty(customerList)) {
			customerObj = customerList.get(0);
		} else {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_CUSTOMER_NOT_FOUND,
					MessageKeyManager.getMessage("error.customerNotFound"));
		}
		accountNumber = customerObj.getAccountNumber().toUpperCase();
		if (accountController.isAccountExist(accountNumber) == null) {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_ACCOUNT_NOT_FOUND,
					MessageKeyManager.getMessage("error.accountNotFound"));
		} else {
			accountObj = accountController
					.getAccountByAccountNumber(accountNumber);
			customerObj.setAccount(accountObj);
		}
		return customerObj;
	}

	public Customer getCustomerByAccount(String accountNumber)
			throws ControllerException {
		List<Customer> customerList = null;
		Customer customerObj = null;
		Account accountObj = null;
		AccountController accountController = new AccountController();
		Selector selector = new Selector();
		selector.eq("accountNumber", accountNumber);
		try {
			customerList = dataStorage.loadObjectsBySelector(Customer.class,
					selector);
		} catch (DataStoreException e) {
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
		if (!Util.isEmpty(customerList)) {
			customerObj = customerList.get(0);
		} else {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_CUSTOMER_NOT_FOUND,
					MessageKeyManager.getMessage("error.customerNotFound"));
		}
		if (accountController.isAccountExist(accountNumber) == null) {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_ACCOUNT_NOT_FOUND,
					MessageKeyManager.getMessage("error.accountNotFound"));
		} else {
			accountObj = accountController
					.getAccountByAccountNumber(accountNumber);
			customerObj.setAccount(accountObj);
		}
		return customerObj;
	}

	public boolean validateCustomerID(Customer customerObj)
			throws ControllerException {
		String custID = customerObj.getId();
		if (Util.isEmpty(custID)) {
			throw new ControllerException(
					ErrorCodeConstants.ERROR_CUSTOMER_NOT_FOUND,
					MessageKeyManager.getMessage("error.customerNotFound"));
		} else {
			return true;
		}
	}

	public void addCustomer(String accountNumber, Customer customerObj)
			throws ControllerException {
		Customer custObj = null;
		String customerNRIC = customerObj.getNRIC().toUpperCase();
		try {
			// set customer as active
			customerObj.setNRIC(customerNRIC);
			customerObj.setActive(RecordState.ACTIVE);

			// Adding the new customer, controller must help to add accountObj
			// for
			// it.
			Account accountObj = new Account();
			accountObj.setAccountNumber(accountNumber);
			accountObj.setCustomer(customerObj);
			accountObj.setActive(RecordState.ACTIVE);
			customerObj.setAccount(accountObj);

			// check if customer is exist
			custObj = isNRICExist(customerNRIC);
			if (custObj != null) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_CUSTOMER_DUPLICATION,
						MessageKeyManager
								.getMessage("error.customerDuplication"));
			} else {
				dataStorage.saveObject(customerObj);
				dataStorage.saveObject(accountObj);
			}
		} catch (DataStoreException e) {
			e.printStackTrace();
			throw new ControllerException(ErrorCodeConstants.ERROR_DATASTORE,
					MessageKeyManager.getMessage("error.dataStore"));
		}
	}

	public void deleteCustomer(Customer customerObj) throws ControllerException {
		if (validateCustomerID(customerObj)) {
			try {
				customerObj.setActive(RecordState.DELETED);
				dataStorage.saveObject(customerObj);
			} catch (DataStoreException e) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_DATASTORE,
						MessageKeyManager.getMessage("error.dataStore"));
			}
		}
	}

	public void restoreCustomer(Customer customerObj)
			throws ControllerException {
		if (validateCustomerID(customerObj)) {
			try {
				customerObj.setActive(RecordState.ACTIVE);
				dataStorage.saveObject(customerObj);
			} catch (DataStoreException e) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_DATASTORE,
						MessageKeyManager.getMessage("error.dataStore"));
			}
		}
	}

	public void editCustomer(Customer customerObj) throws ControllerException {
		if (validateCustomerID(customerObj)) {
			try {
				dataStorage.saveObject(customerObj);
			} catch (DataStoreException e) {
				throw new ControllerException(
						ErrorCodeConstants.ERROR_DATASTORE,
						MessageKeyManager.getMessage("error.dataStore"));
			}
		}
	}
}
